/**
 * @file export.h
 * @author Linquan  
 * @brief 存在两种export机制，均基于GNUC构建
 *      （1）export with constructor and destructor
 *      （2）export with arg
 *  1、本框架使用的是第二种export with arg方式构建。需搭配export.c使用。
 *      可以通过输入参数指针，传入参数，供内部调用。当没有参数时，传入 NULL [(void*)0]
 *  2、第一种是纯宏定义，用于main函数前初始化某些模块。例如替换动态内存mello。
 *  详细使用举例，见 TEST_export_with_constroctor.C
 * 
 * @version 1.0
 * @date 2024-06-12
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef EXPORT_H
#define EXPORT_H

#include "stddef.h"

/*****************************************************************************************
 * ------ export with constructor and destructor ----
 * 
 *  构造析构：
 *   __attribute__((constructor)) 先于main()函数调用
 *   __attribute__((destructor))在main()函数后调用
 *
 *  1、构造函数先于main函数而执行
 *      不同构造函数如果在同一个文件中，则先出现的函数后执行
 *      对于不同文件中的构造函数，编译命令中后出现的.c文件的构造函数先执行          
 *  2、析构函数后于main函数执行，
 *  序号高先执行，同一序号，对于声明函数先出现的后执行
 *  method：
 *      使用 EXPORT_CONSTRUCTOR 定义函数名，并设置优先级（优先级>100,优先级越小，先执行。在main函数前执行。
 *      使用 EXPORT_DESTRUCTOR 定义函数名，并设置优先级（优先级>100,优先级越大，先执行。在main函数后执行。
 *
 *      对已经定义好的函数，使用CONSTRUCTOR(prio_num)、DESTRUCTOR(prio_num)宏进行声明添加。
 *******************************************************************************************/

/* 构造函数宏 */
#define CONSTRUCTOR(prio_num) __attribute__((constructor(prio_num)))
/* 析构函数宏 */
#define DESTRUCTOR(prio_num) __attribute__ ((destructor(prio_num)))

/* 构造函数宏声明 */
#define EXPORT_CONSTRUCTOR(func_name , level)   CONSTRUCTOR(level) void func_name () 
/* 析构函数宏声明 */
#define EXPORT_DESTRUCTOR(func_name , level)   DESTRUCTOR(level) void func_name () 


/***************** API：构造函数添加 ****************************/
#define EXPORT_CONSTRUCTOR_FIRST(func_name)   EXPORT_CONSTRUCTOR(func_name , 101)
#define EXPORT_CONSTRUCTOR_SECOND(func_name)   EXPORT_CONSTRUCTOR(func_name , 102)
#define EXPORT_CONSTRUCTOR_THIRD(func_name)   EXPORT_CONSTRUCTOR(func_name , 103)

/***************** API：析构函数添加 ****************************/
#define EXPORT_CONSTRUCTOR_FINAL(func_name)   EXPORT_CONSTRUCTOR(func_name , 101)







/****************************************************
 * -------- export with arg  ------------
 * 
 * 带有参数传入的export机制，共分为7级。
 *     在main函数中通过调用下方函数进行执行
 *         void export_mode_all_init(void);
 *         void export_mode_app_mange(void);
 *     method：
 *     宏：EXPORT_Lv1_BOARD ～ EXPORT_Lv6_APP_INIT，用于分级调用初始化函数及单次执行的函数
 *     宏：EXPORT_Lv7_APP_MANGE，用于循环执行应用函数
 ****************************************************/

/* 添加模块到指定段 */
#define SECTION(level)  __attribute__((used, __section__("model_"#level), aligned(sizeof(void *))))
#define CMD_EXPORT(level,func,func_arg) const  CMD_LIST model##func SECTION(level) = {func,func_arg}

/* 自定义段名的首尾 声明。 
    如果在KEIL中，需要关闭 GNC extern选项 或删掉 _GNUC_ 的宏定义
*/
#ifdef ARMCC_VERSION 
    #define SECTION_MOD_START(level) model_##level##$$Base
    #define SECTION_MOD_STOP(level)  model_##level##$$Limit
#elif defined (__GNUC__)
    #define SECTION_MOD_START(level) __start_model_##level
    #define SECTION_MOD_STOP(level)  __stop_model_##level
#else   
      #error "The platform is not supported"
#endif

/* 声明export模块结构体 */
typedef void (*export_fun_mod)( void *cmd);
typedef struct 
{
    export_fun_mod funs;
     void *cmd;
}CMD_LIST;


/***************** API：模块添加 ****************************/

/* 板级初始化 */
#define EXPORT_Lv1_BOARD(func,func_arg)        CMD_EXPORT(1,func,func_arg)

/* 无过多依赖的纯软件预先初始化，用于调度器初始化 */
#define EXPORT_Lv2_PREV(func,func_arg)         CMD_EXPORT(2,func,func_arg)

/* 设备初始化 */
#define EXPORT_Lv3_DEVICE(func,func_arg)       CMD_EXPORT(3,func,func_arg)

/* 有依赖的组件初始化 */
#define EXPORT_Lv4_COMPONENT(func,func_arg)    CMD_EXPORT(4,func,func_arg)  

/* 系统环境初始化 */
#define EXPORT_Lv5_ENVIRMENT(func,func_arg)    CMD_EXPORT(5,func,func_arg)  

/* 应用初始化 或用于单次执行的函数 */
#define EXPORT_Lv6_APP_INIT(func,func_arg)     CMD_EXPORT(6,func,func_arg)
#define EXPORT_Lv6_APP_SINGLE(func,func_arg)   CMD_EXPORT(6,func,func_arg)

//----------------------------------------//
/* 应用任务组织管理 用于循环执行的函数 */
#define EXPORT_Lv7_APP_MANGE(func,func_arg)     CMD_EXPORT(7,func,func_arg)



/************export 调用***************/
void export_mode_all_init(void);
void export_mode_app_mange(void);



#endif